//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioControls.RegistryManagerModule
{
    using System;
    using System.ComponentModel;
    using System.Text;
    using System.Windows;
    using ManagementStudioServices.Interfaces;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioControls.Common;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using Microsoft.Practices.Unity;
    using Microsoft.Win32;
    using SR = Microsoft.Research.DataLayer;
    using System.Globalization;

    /// <summary>
    /// Presentation logic for DataReferenceProviderCenterPanePresenter.
    /// </summary>
    public class DataReferenceProviderCenterPanePresenter : IRegistryManagerCenterPanePresenter, INotifyPropertyChanged
    {
        /// <summary>
        /// The unity container.
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Service for registry access.
        /// </summary>
        private IRegistryManagerService registryManagerService;

        /// <summary>
        /// Editable model.
        /// </summary>
        private DataReferenceProviderModel currentModel;

        /// <summary>
        /// Selected model.
        /// </summary>
        private DataReferenceProviderModel selectedModel;

        /// <summary>
        /// The current model.
        /// </summary>
        public DataReferenceProviderModel CurrentModel
        {
            get
            {
                return this.currentModel;
            }
            set
            {
                this.currentModel = value;
                this.RaisePropertyChanged("CurrentModel");
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="DataReferenceProviderCenterPanePresenter"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="contentView">The content view.</param>
        /// <param name="service">The service.</param>
        public DataReferenceProviderCenterPanePresenter(
            IUnityContainer container,
            DataReferenceProviderCenterPane contentView,
            IRegistryManagerService service)
        {
            this.container = container;
            this.ContentView = contentView;
            this.registryManagerService = service;

            contentView.DataContext = this;

            this.SaveChangesCommand = new DelegateCommand<object>(p => this.SaveChangesExecute());
            this.CancelChangesCommand = new DelegateCommand<object>(p => this.CancelChangesExecute());
            this.ImportCommand = new DelegateCommand<object>(p => this.ImportCommandExecute());
            this.DeleteProviderCommand = new DelegateCommand<object>(p => this.DeleteProviderCommandExecute());
            this.CreateNewStoreCommand = new DelegateCommand<object>(p => this.CreateNewStoreCommandExecute());
        }

        /// <summary>
        /// Gets or sets the save changes command.
        /// </summary>
        /// <value>The save changes command.</value>
        public DelegateCommand<object> SaveChangesCommand { get; private set; }

        /// <summary>
        /// Gets or sets the cancel changes command.
        /// </summary>
        /// <value>The cancel changes command.</value>
        public DelegateCommand<object> CancelChangesCommand { get; private set; }

        /// <summary>
        /// Gets or sets the import command.
        /// </summary>
        /// <value>The import command.</value>
        public DelegateCommand<object> ImportCommand { get; private set; }

        /// <summary>
        /// Gets or sets the delete provider command.
        /// </summary>
        /// <value>The delete provider command.</value>
        public DelegateCommand<object> DeleteProviderCommand { get; private set; }

        /// <summary>
        /// Gets or sets the create new store command.
        /// </summary>
        /// <value>The create new store command.</value>
        public DelegateCommand<object> CreateNewStoreCommand { get; private set; }

        #region IRegistryManagerCenterPanePresenter Members

        /// <summary>
        /// Gets or sets the content view.
        /// </summary>
        /// <value>The content view.</value>
        public System.Windows.UIElement ContentView { get; set; }

        /// <summary>
        /// Gets or sets the refresh command.
        /// </summary>
        /// <value>The refresh command.</value>
        public DelegateCommand<BaseRegMgrModel> RefreshCommand { get; set; }

        /// <summary>
        /// Gets or sets the delete command.
        /// </summary>
        /// <value>The delete command.</value>
        public DelegateCommand<BaseRegMgrModel> DeleteCommand { get; set; }

        /// <summary>
        /// Gets or sets the update command.
        /// </summary>
        /// <value>The delete command.</value>
        public DelegateCommand<BaseRegMgrModel> UpdateCommand { get; set; }

        /// <summary>
        /// Gets or sets the select root command.
        /// </summary>
        /// <value>The select root command.</value>
        public DelegateCommand<object> SelectRootCommand { get; set; }

        /// <summary>
        /// Gets or sets the selected model.
        /// </summary>
        /// <value>The selected model.</value>
        public BaseRegMgrModel SelectedModel
        {
            get
            {
                return this.selectedModel;
            }
            set
            {
                this.selectedModel = value as DataReferenceProviderModel;

                if (this.selectedModel != null)
                {
                    Guid currentID = this.selectedModel.Id;

                    if (this.CurrentModel != null && !this.CurrentModel.Id.Equals(currentID))
                    {
                        this.container.Resolve<IStatusMessageControl>().SetText(string.Empty);
                    }
                }

                this.CurrentModel = DataReferenceProviderModel.CreateClone(this.selectedModel);
                this.RaisePropertyChanged("SelectedModel");
            }
        }

        /// <summary>
        /// Saves the changes.
        /// </summary>
        /// <returns>
        /// An enum value indicating the save status of the save operation, it can be Valid or Invalid.
        /// </returns>
        public SaveStateHandler SaveChanges()
        {
            return this.EnforceSaveChanges();
        }

        #endregion

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises the property changed.
        /// </summary>
        /// <param name="name">The name.</param>
        protected void RaisePropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Saves the changes execute.
        /// </summary>
        /// <param name="saveSuccess">The save success.</param>
        private void SaveChangesExecute()
        {
            bool saveSucceeded = true;
            SR.DataReferenceProvider provider = null;
            StringBuilder errorMsg = new StringBuilder();
            try
            {
                // Save the changed data reference provider.
                provider = this.registryManagerService.SaveDataReferenceProvider(this.CurrentModel);
                if (null == provider)
                {
                    saveSucceeded = false;
                }
            }
            catch (TridentCustomException ex)
            {
                errorMsg.Append(ex.Message);
                saveSucceeded = false;
            }

            if (saveSucceeded)
            {
                this.selectedModel.Update(provider);
                this.CurrentModel = DataReferenceProviderModel.CreateClone(this.selectedModel);

                this.container.Resolve<IStatusMessageControl>()
                    .SetText(ManagementStudioResourceManager.GetString("DataProviderSaveSuccess"));
            }
            else
            {
                TridentMessageBox.ShowTridentErrorMessageBox(errorMsg.ToString());
            }
        }

        /// <summary>
        /// Cancels the changes execute.
        /// </summary>
        private void CancelChangesExecute()
        {
            this.Rollback();
            if (this.SelectRootCommand != null)
            {
                this.SelectRootCommand.Execute(null);
            }
        }

        /// <summary>
        /// Imports the command execute.
        /// </summary>
        private void ImportCommandExecute()
        {
            SaveStateHandler saveStatus = this.EnforceSaveChanges();
            if (saveStatus.SaveOptionSelected == SaveStatus.Valid)
            {
                OpenFileDialog openDialog = new OpenFileDialog();

                // Filters the type dll in the current Directory.
                openDialog.Filter = "Data reference provider assemblies |*.dll; *.exe";

                // Checks and promts the user if the file is not present in the directory.
                openDialog.CheckFileExists = true;

                // Check if File Exists in directory Specified.
                openDialog.CheckPathExists = true;

                // Restores the previous Directory the user had selected to Open/Save the file.
                openDialog.RestoreDirectory = true;

                if ((bool)openDialog.ShowDialog())
                {
                    bool? importSucceeded = false;
                    string message = TridentResourceManager.GetString("ImportDataReferenceProviderFailed");
                    StringBuilder strBuilder = new StringBuilder(message);
                    try
                    {
                        // Import the data reference provider.
                        importSucceeded = this.registryManagerService.ImportDataReferenceProvider(openDialog.FileName);
                    }
                    catch (TridentCustomException ex)
                    {
                        message = string.Format(CultureInfo.CurrentCulture, "{0} {1}", message, ex.Message);
                    }
                    catch (Exception ex)
                    {
                        TridentErrorHandler.HandleUIException(ex);
                        message = string.Format(CultureInfo.CurrentCulture, "{0} {1}", message, ex.Message);
                    }

                    if (importSucceeded != null)
                    {
                        if ((bool)importSucceeded)
                        {
                            if (this.RefreshCommand != null)
                            {
                                this.RefreshCommand.Execute(this.CurrentModel);
                            }

                            // Clear all the existing external registry files and then remove the temp files.
                            SR.ExternalRegistryHelperProxy.CleanUp();

                            this.container.Resolve<IStatusMessageControl>()
                                .SetText(ManagementStudioResourceManager.GetString("ImportDataReferenceProviderSuccess"));
                        }
                        else
                        {
                            TridentMessageBox.ShowTridentErrorMessageBox(message);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Deletes the data reference provider command execute.
        /// </summary>
        private void DeleteProviderCommandExecute()
        {
            MessageBoxResult res = TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(
                ManagementStudioResourceManager.GetString("DataReferenceProviderDeleteConfirmationMsg"));
            if (res == MessageBoxResult.Yes)
            {
                try
                {
                    bool deleteSuccess = this.registryManagerService.DeleteDataReferenceProvider(this.CurrentModel);
                    if (deleteSuccess)
                    {
                        if (this.DeleteCommand != null)
                        {
                            this.DeleteCommand.Execute(this.CurrentModel);
                        }
                    }
                    else
                    {
                        TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("DataReferenceProviderDeleteError"));
                    }
                }
                catch (TridentCustomException ex)
                {
                    TridentMessageBox.ShowTridentErrorMessageBox(ex.Message);
                }
            }
        }

        /// <summary>
        /// Creates the new store command execute.
        /// </summary>
        private void CreateNewStoreCommandExecute()
        {
            // Create the data store model.
            DataReferenceStoreModel model = new DataReferenceStoreModel(string.Empty, this.SelectedModel as DataReferenceProviderModel);

            // Add to parent provider.
            this.SelectedModel.Children.Add(model);
            model.IsSelected = true;
        }

        /// <summary>
        /// Enforces the save changes.
        /// </summary>
        /// <returns></returns>
        private SaveStateHandler EnforceSaveChanges()
        {
            SaveStateHandler saveState = new SaveStateHandler(SaveStatus.Valid);
            if (this.CurrentModel != null && !this.CurrentModel.Equals(this.SelectedModel as DataReferenceProviderModel))
            {
                MessageBoxResult userResult = TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(
                    ManagementStudioResourceManager.GetString("DataReferenceProviderChangeQuestion"));
                if (userResult == MessageBoxResult.Yes)
                {
                    // Save the changes.
                    this.SaveChangesCommand.Execute(null);
                }
                else if (userResult == MessageBoxResult.No)
                {
                    this.Rollback();
                }
            }

            return saveState;
        }

        /// <summary>
        /// Rollbacks this instance.
        /// </summary>
        private void Rollback()
        {
            if (this.SelectedModel != null)
            {
                this.CurrentModel = DataReferenceProviderModel.CreateClone(this.SelectedModel as DataReferenceProviderModel);
            }
        }

        #endregion Private Methods
    }
}
